﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using PmSoft.Core.Domain.Auth;
using PmSoft.Web.Abstractions.Attributes;
using PmSoft.Web.Abstractions.ErrorCode;

namespace PmSoft.Web.Abstractions.Authorization;

/// <summary>
/// 自定义授权处理器，用于处理基于菜单权限的授权需求。
/// 验证当前用户是否拥有指定的菜单权限，基于 <see cref="MenuAuthorizeAttribute"/> 中定义的菜单代码。
/// </summary>
public class MenuAuthorizationHandler : AttributeAuthorizationHandler<MenuAuthorizationRequirement, MenuAuthorizeAttribute>
{
	/// <summary>
	/// 处理授权要求，检查用户是否满足指定的菜单权限。
	/// 如果用户未认证、上下文无效或缺少所需权限，则授权失败；否则授权成功。
	/// </summary>
	/// <param name="context">授权上下文，包含用户信息和授权状态。</param>
	/// <param name="requirement">菜单权限要求，通常由策略定义。</param>
	/// <param name="attributes">应用于目标的 <see cref="MenuAuthorizeAttribute"/> 集合，包含所需的菜单代码。</param>
	/// <returns>异步任务，表示授权处理已完成。</returns>
	protected override async Task HandleRequirementAsync(
		AuthorizationHandlerContext context,
		MenuAuthorizationRequirement requirement,
		IEnumerable<MenuAuthorizeAttribute> attributes)
	{
		// 确保上下文和参数有效
		if (context == null) throw new ArgumentNullException(nameof(context));
		if (attributes == null || !attributes.Any()) throw new ArgumentNullException(nameof(attributes));

		// 检查用户是否已认证
		var user = context.User;
		if (user?.Identity?.IsAuthenticated != true)
		{
			context.Fail(); // 未认证，授权失败
			return;
		}

		// 获取 HTTP 上下文
		if (context.Resource is not DefaultHttpContext httpContext)
		{
			context.Fail(); // 无法获取 HTTP 上下文，授权失败
			return;
		}

		// 从 DI 容器中获取权限检查服务
		var permissionChecker = httpContext.RequestServices.GetRequiredService<CachedMenuPermissionChecker>();
		if (permissionChecker == null)
		{
			context.Fail(); // 权限检查服务未注册，授权失败
			return;
		}

		// 获取当前用户
		var currentUser = httpContext.Items["CurrentUser"] as IAuthedUser;
		if (currentUser == null)
		{
			//当前用户未设置，授权失败
			var errorCodeDefinition = ErrorCodeManager.GetError("UNAUTHENTICATED");
			SetFailure(context, httpContext, errorCodeDefinition.HttpStatus, errorCodeDefinition.Code, "身份验证失败，请提供有效的凭据");
			return;
		}

		//超级管理员拥有所有菜单权限
		if (currentUser.IsSuperAdmin())
		{
			context.Succeed(requirement);
			return;
		}

		// 检查用户是否拥有所有必需的菜单权限
		var requiredPermCodes = attributes.SelectMany(m => m.RequiredPermCodes).Distinct().ToArray();
		if (await permissionChecker.HasPermissionAsync(currentUser, requiredPermCodes))
		{
			context.Succeed(requirement); // 权限满足，授权成功
		}
		else
		{
			var errorCodeDefinition = ErrorCodeManager.GetError("FORBIDDEN");
			// 权限不满足，授权失败
			SetFailure(context, httpContext, errorCodeDefinition.HttpStatus, errorCodeDefinition.Code, "您没有访问此资源的权限");
		}
	}

	private static void SetFailure(AuthorizationHandlerContext context, DefaultHttpContext? httpContext, int statusCode, string code, string message)
	{
		context.Fail();
		if (httpContext != null)
		{
			httpContext.Items["AuthFailure"] = new AuthFailureInfo(statusCode, code, message);
		}
	}
}